package org.example.util;

import lombok.*;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;

@Data
public class Image {
    private byte[] imageByte;//图片缓冲数组
    private float x;//坐标x
    private float y;//坐标y
    private int indexPage;//签名放在那一页（从1开始）
    private float zoom;//缩放比例，默认缩小一半
    private float imageWidth;//经过 scale 放大/缩小后的图片 宽 zoom
    private float imageHeight;//经过 scale 放大/缩小后的图片 高
    private String errMessage = "图片展示失败";//图片展示异常时展示内容
    private KeyWords keyWords;//查询坐标位置关键词
    private BiasedPosition biasedPosition = BiasedPosition.RIGHT;//坐标偏置位置位置（默认偏右）
    private boolean isSignImage;//是不是签名使用图片（区别：签名，坐标原点在左上角；非签名，坐标原点在左下角）

    public Image() {
    }

    /**
     * 仅用于包装数据，不做计算使用
     *
     * @param imageByte 图片字节数组
     * @param x         X坐标
     * @param y         Y坐标
     * @param zoom      缩放比例 -50F
     * @param indexPage 图片添加在那一页（从1开始）
     */
    public Image(byte[] imageByte, float x, float y, float zoom, int indexPage) {
        this.imageByte = imageByte;
        this.x = x;
        this.y = y;
        this.zoom = zoom;
        this.indexPage = indexPage;
    }

    /**
     * @param imageByte   图片字节数组
     * @param keyWords    关键字坐标位置
     * @param isSignImage 是不是签名使用的图片
     * @throws IOException
     */
    public Image(byte[] imageByte, KeyWords keyWords, boolean isSignImage) throws IOException {
        this(imageByte, -50F, keyWords, isSignImage);
    }

    /**
     * @param imageByte   图片字节数组
     * @param zoom        图片缩放比例，默认：-50F（如果是签名图片，则 缩放比例 zoom 必须要与 签名图片中设置的比例大小一致；例如 visibleSignDesigner.zoom(-50)）
     * @param keyWords    关键字坐标位置
     * @param isSignImage 是不是签名使用的图片
     */
    public Image(byte[] imageByte, float zoom, KeyWords keyWords, boolean isSignImage) throws IOException {
        this.imageByte = imageByte;
        this.zoom = zoom;
        this.indexPage = keyWords.getCurrentPageNo();
        this.keyWords = keyWords;
        this.isSignImage = isSignImage;
        this.imageBuild();//图片宽高处理
    }

    /**
     * 对象中必要数据都赋值完毕后，执行坐标计算处理
     * 图片宽高处理
     *
     * @throws IOException
     */
    public void imageBuild() throws IOException {
        try (ByteArrayInputStream stream = new ByteArrayInputStream(this.imageByte)) {
            BufferedImage bufferedImage = ImageIO.read(stream);
            this.imageWidth = scaleRatio(bufferedImage.getWidth());
            this.imageHeight = scaleRatio(bufferedImage.getHeight());
            if (this.isSignImage) {
                this.getSignXY();
            } else {
                this.getXY();
            }
        }
    }


    /**
     * 计算缩放比
     *
     * @param length 长度
     * @return 计算缩放比例后的长度
     */
    private float scaleRatio(float length) {
        length += (length * this.zoom) / 100;
        return length;
    }


    /**
     * 重新计算坐标值
     */
    public void reCompute() {
        //设置坐标默认值——右侧
        if (this.isSignImage) {
            this.getSignXY();
        } else {
            this.getXY();
        }
    }


    /**
     * 【普通图片使用】 设置、修改坐标的偏向位置 上、下、左、右 <br>
     * 获取的普通图片坐标位置（左下角坐标原点）  <br>
     * 获取的坐标位图片[左下角]的坐标值，图片[向右，向上]展开  <br>
     *
     * @see BiasedPosition
     */
    public void getXY() {
        //获取关键字坐标对象
        switch (biasedPosition) {
            case TOP://上
                this.x = (keyWords.getLeftX() + keyWords.getRightX()) / 2 - imageWidth / 2;
                this.y = keyWords.getDown_TopY() + keyWords.getSpaceLength();//加上空格是为了增减适当的间距
                break;
            case BOTTOM://下
                this.x = (keyWords.getLeftX() + keyWords.getRightX()) / 2 - imageWidth / 2;
                this.y = keyWords.getDown_BottomY() - imageHeight - keyWords.getSpaceLength();//减去空格是为了增减适当的间距
                break;
            case LEFT://左
                this.x = keyWords.getLeftX() - imageWidth - keyWords.getSpaceLength();//减去空格是为了增减适当的间距
                this.y = (keyWords.getDown_TopY() + keyWords.getDown_BottomY()) / 2 - imageHeight / 2;
                break;
            case RIGHT://右
                this.x = keyWords.getRightX() + keyWords.getSpaceLength();//加上空格是为了增减适当的间距
                this.y = (keyWords.getDown_TopY() + keyWords.getDown_BottomY()) / 2 - imageHeight / 2;
                break;
            case CENTER://中
                this.x = (keyWords.getLeftX() + keyWords.getRightX()) / 2 - imageWidth / 2;
                this.y = (keyWords.getDown_TopY() + keyWords.getDown_BottomY()) / 2 - imageHeight / 2;
                break;
        }
    }

    /**
     * 【签名图片使用】 设置、修改坐标的偏向位置 上、下、左、右 <br>
     * 获取签名图片坐标位置（左上角坐标原点）  <br>
     * 获取的坐标位图片[左上角]的坐标值，图片[向右，向下]展开  <br>
     *
     * @see BiasedPosition
     */
    public void getSignXY() {
        //获取关键字坐标对象
        switch (biasedPosition) {
            case TOP://上
                this.x = (keyWords.getLeftX() + keyWords.getRightX()) / 2 - imageWidth / 2;
                this.y = keyWords.getTop_TopY() - imageHeight - keyWords.getSpaceLength();//减去空格是为了增减适当的间距
                break;
            case BOTTOM://下
                this.x = (keyWords.getLeftX() + keyWords.getRightX()) / 2 - imageWidth / 2;
                this.y = keyWords.getTop_BottomY() + keyWords.getSpaceLength();//加上空格是为了增减适当的间距
                break;
            case LEFT://左
                this.x = keyWords.getLeftX() - imageWidth - keyWords.getSpaceLength();//减去空格是为了增减适当的间距
                this.y = (keyWords.getTop_TopY() + keyWords.getTop_BottomY()) / 2 - imageHeight / 2;
                break;
            case RIGHT://右
                this.x = keyWords.getRightX() + keyWords.getSpaceLength();//加上空格是为了增减适当的间距
                this.y = (keyWords.getTop_TopY() + keyWords.getTop_BottomY()) / 2 - imageHeight / 2;
                break;
            case CENTER://中
                this.x = (keyWords.getLeftX() + keyWords.getRightX()) / 2 - imageWidth / 2;
                this.y = (keyWords.getTop_TopY() + keyWords.getTop_BottomY()) / 2 - imageHeight / 2;
                break;
        }
    }


    /**
     * 图片格式转换
     *
     * @param inputStream 原始图片输入流
     * @param formatName  要转换成的图片格式，例如 "png", "jpg", "gif"
     */
    public static ByteArrayOutputStream convertImageFormat(InputStream inputStream, String formatName) throws IOException {
        // 读取图片文件
        BufferedImage image = ImageIO.read(inputStream);
        // 写出图片文件
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageIO.write(image, formatName, byteArrayOutputStream);
        return byteArrayOutputStream;
    }


    /**
     * 转换 BufferedImageToByte
     *
     * @param bufferedImage 图片数据
     * @return 图片byte数组
     * @throws IOException
     */
    public static byte[] BufferedImageToByte(BufferedImage bufferedImage) throws IOException {
        try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
            ImageIO.write(bufferedImage, "png", stream);//png：指定要生成的图片的格式类型 例如：png、gif
            return stream.toByteArray();
        }
    }


    /**
     * 转换 BufferedImageToByte
     *
     * @param imageByte 图片字节数组
     * @return BufferedImage
     * @throws IOException
     */
    public static BufferedImage ByteToBufferedImage(byte[] imageByte) throws IOException {
        try (ByteArrayInputStream stream = new ByteArrayInputStream(imageByte)) {
            return ImageIO.read(stream);
        }
    }


    //偏置位置
    public enum BiasedPosition {
        TOP, //上
        BOTTOM,//下
        LEFT,//左
        RIGHT,//右
        CENTER//中
    }


    public static void main(String[] args) throws IOException {
        byte[] imageByte = null;
        String inPath = "D:\\zhong.pdf";
        PDDocument doc = Loader.loadPDF(new File(inPath));
        KeyWords keywordsSig = new KeyWords("投保人签章：", true, doc);
        Image imageSig = new Image(imageByte, -50, keywordsSig, true);
        //修改图片方位
        imageSig.setBiasedPosition(Image.BiasedPosition.LEFT);
        imageSig.reCompute();


        //KeyWords keywordsSig = new KeyWords("投保人签章：", true, doc);
        //Image imageSig = new Image(Image.BufferedImageToByte(visibleSignDesigner.getImage()), -50,keywordsSig,true);


    }

}
